using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using MacomberMap.Common.Types;
using MacomberMap.Common.Internals;
using MacomberMap.Common.User_Interfaces.Components;
using MacomberMap.Common.Components;
using System.Windows.Forms;
using System.Collections;
using System.Reflection;

namespace MacomberMap.Common.Events
{
    /// <summary>
    /// This class covers alarms, Events, and other events that will be shown in the viewer
    /// </summary>
    public abstract class MM_Event : MM_Element, IComparable
    {
        #region Variable declarations
        /// <summary>The randomizer for creating new TEIDs.</summary>
        public static Random TEIDRandomizer = new Random();        

        /// <summary>The date/time of the event</summary>
        public DateTime EventTime;

        /// <summary>The type of event represented by this event</summary>
        public MM_Event_Type EventType;

        /// <summary>Whether this Event is flagged as new</summary>
        public enum EventStateEnum { 
            /// <summary>A new event is in the log</summary>
            New,
            /// <summary>An event has been given ownership</summary>
            Owned,
            /// <summary>An event has been acknowledged</summary>
            Acknowledged,
            /// <summary>An event has been closed</summary>
            Closed };

        /// <summary>The current state of the event</summary>
        public EventStateEnum EventState = EventStateEnum.New;

        /// <summary>
        /// Return the text of the item's recency
        /// </summary>
        public String TimeText
        {
            get
            {
                if (MM_Overall_Display.DeltaTime)
                {                   
                    TimeSpan DeltaTime = DateTime.Now - EventTime;
                    if (DeltaTime.TotalMinutes < 60)
                        return "00:" + DeltaTime.TotalMinutes.ToString("00");
                    else
                        return DeltaTime.TotalHours.ToString("#,##0") + ":" + DeltaTime.Minutes.ToString("00");
                }
                else
                    return EventTime.ToString("HH:mm:ss");
            }
        }
        #endregion
        #region Initialization
        /// <summary>
        /// Initialze a new event
        /// </summary>
        public MM_Event()
        {
            this.EventTime = DateTime.Now;
            String ThisType = this.GetType().Name.Substring(9);
            if (!MM_Overall_Display.EventTypes.TryGetValue(ThisType, out this.EventType))
                MM_Overall_Display.EventTypes.Add(ThisType, this.EventType = new MM_Event_Type(ThisType));

            //Now, randomly determine the TEID
            while (this.TEID == 0 || MM_Repository.Events.ContainsKey(this.TEID))
            {
                byte[] outBytes = new byte[8];
                TEIDRandomizer.NextBytes(outBytes);
                this.TEID = BitConverter.ToUInt64(outBytes, 0);
            }

        }
        #endregion

        #region Abstract methods
        /// <summary>
        /// Build a list view item for the event in question
        /// </summary>
        /// <returns></returns>
        public abstract ListViewItem BuildListViewItem();

        /// <summary>
        /// Update a list view item to reflect current conditions
        /// </summary>
        /// <param name="lvItem">The list view item to be updated</param>
        public abstract void UpdateListViewItem(ListViewItem lvItem);

        /// <summary>
        /// Display the details of this event in its panel
        /// </summary>
        /// <param name="OutParent">The parent holding the controls</param>
        public abstract void DisplayDetails(Control OutParent);

        /// <summary>
        /// Add all applicable menu options to the right-click menu options
        /// </summary>
        /// <param name="OutMenu"></param>
        public abstract void AddMenuItems(ContextMenuStrip OutMenu);

        /// <summary>
        /// Add an item to a node collection
        /// </summary>
        /// <param name="ItemName">The name of the item</param>
        /// <param name="Item">The item to be added</param>
        /// <param name="ParentCollection">The collection of parent nodes</param>
        /// <returns></returns>
        public TreeNode AddNodeItem(String ItemName, Object Item, TreeNodeCollection ParentCollection)
        {
            if (!String.IsNullOrEmpty(ItemName))
                ItemName += ": ";
            if (Item is IList)
            {
                TreeNode OutNode = ParentCollection.Add(ItemName);
                foreach (Object SubItem in (Item as IList))
                    AddNodeItem("", SubItem, OutNode.Nodes);
                return OutNode;
            }
            else if (Item is IDictionary)
            {
                TreeNode OutNode = ParentCollection.Add(ItemName);
                foreach (KeyValuePair<object, object> kvp in (Item as IDictionary))
                    AddNodeItem("", kvp.Key.ToString() + " = " + kvp.Value.ToString(), OutNode.Nodes);
                return OutNode;
            }
            else if (Item == null)
                return ParentCollection.Add(ItemName);
            else if (Item is MM_Element)
            {
                TreeNode OutNode = ParentCollection.Add(ItemName + Item.ToString());
                foreach (FieldInfo fI in Item.GetType().GetFields())
                    try
                    {
                        AddNodeItem(fI.Name, fI.GetValue(Item), OutNode.Nodes);
                    }
                    catch (Exception ex)
                    {
                        AddNodeItem(fI.Name, "ERROR: " + ex.Message, OutNode.Nodes);
                    }
                return OutNode;

            }
            else if (Item.GetType().Name == "CIM_Element" || Item.GetType().UnderlyingSystemType.Name == "CIM_Element")
            {
                TreeNode OutNode = ParentCollection.Add(ItemName + Item.ToString());
                foreach (FieldInfo fI in Item.GetType().GetFields())
                    try
                    {
                        AddNodeItem(fI.Name, fI.GetValue(Item), OutNode.Nodes);
                    }
                    catch (Exception ex)
                    {
                        AddNodeItem(fI.Name, "ERROR: " + ex.Message, OutNode.Nodes);
                    }
                return OutNode;
            }

            else if (Item is Array)
            {
                TreeNode OutNode = ParentCollection.Add(ItemName);
                foreach (Object obj in (Item as Array))
                    AddNodeItem("", obj, OutNode.Nodes);
                return OutNode;
            }

            else
                return ParentCollection.Add(ItemName + Item.ToString());                
        }
        #endregion

        /// <summary>
        /// Update the time for this event
        /// </summary>
        public void UpdateTime(ListViewItem lvI)
        {
            lvI.SubItems[2].Text = TimeText;
        }

        /// <summary>
        /// Provide an interface for comparing objects
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public abstract int CompareTo(object obj);

        
    }
}
